package www.meng.com.serviceImpl;

import cn.hutool.core.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.beetl.sql.clazz.ClassDesc;
import org.beetl.sql.clazz.NameConversion;
import org.beetl.sql.clazz.TableDesc;
import org.beetl.sql.clazz.kit.BeetlSQLException;
import org.beetl.sql.clazz.kit.DefaultKeyWordHandler;
import org.beetl.sql.clazz.kit.KeyWordHandler;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.page.DefaultPageRequest;
import org.beetl.sql.core.page.PageRequest;
import org.beetl.sql.core.page.PageResult;
import org.beetl.sql.core.query.LambdaQuery;
import org.beetl.sql.core.query.Query;
import org.beetl.sql.mapper.BaseMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import www.meng.com.service.BaseService;

import java.util.*;

/**
 * @author : Mr.Yan
 * @program : www.meng.com.serviceImpl
 * @create : 2020/10/22
 * @description : 基于Beelsql3.0版本的实现工具serviceImpl
 */
@Slf4j
@Service
@Transactional
public class BaseServiceImpl<T> implements BaseService<T> {

    @Autowired
    private BaseMapper<T> baseMapper;

    /**
     * @Author : Yan
     * @Create : 2019/12/19
     * @Description :  find this table All date list
     */
    @Override
    public List<T> find_All() {
        return baseMapper.all();
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/19
     * @Description :  find this table all data list size
     */
    @Override
    public long find_All_Size() {
        return baseMapper.allCount();
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/19
     * @Description :  find this table data by primary key
     */
    @Override
    public T find_ObjByPK(Object pk) {
        return baseMapper.single(pk);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/19
     * @Description :  find this table array data by primary key Array
     */
    @Override
    public List<T> find_ListByPKs(List<?> pks) {
        return baseMapper.selectByIds(pks);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :   find this table data by where params
     */
    @Override
    public T find_ObjByWhere(T t) {
        return baseMapper.templateOne(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/19
     * @Description :  find this table data by where params , this params best Map<String,Object> ; but this data list is disorder
     */
    @Override
    public List<T> find_ListByWhere(T t) {
        return baseMapper.template(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/19
     * @Description :  find this table data by where params size , this params best Map<String,Object>
     */
    @Override
    public long find_ListByWhere_Size(T t) {
        return baseMapper.templateCount(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  insert data into this table , include if field is null insert , return primary key
     */
    @Override
    public void insert(T t) {
        baseMapper.insert(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  insert data into this table , include if field is null no insert , return primary key
     */
    @Override
    public void insert_Selective(T t) {
        baseMapper.insertTemplate(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  insert batch data list into this table , return insert success length
     */
    @Override
    public void insert_Batch(List<T> list) {
        baseMapper.insertBatch(list);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description : update data into this table by primary key, include if field is null update , return update size
     */
    @Override
    public int update_ByPK(T t) {
        return baseMapper.updateById(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  update data into this table by primary key, include if field is null no update , return update size
     */
    @Override
    public int update_Selective_ByPK(T t) {
        return baseMapper.updateTemplateById(t);
    }


    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  update batch data list into this table , if field is null update , return insert success length
     */
    @Override
    public int[] update_Batch_ByPK(List<T> list) {
        return baseMapper.getSQLManager().updateByIdBatch(list);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  update batch data list into this table , if field is null no update , return insert success length
     */
    @Override
    public int[] update_BatchSelective_ByPK(List<?> list) {
        return baseMapper.getSQLManager().updateBatchTemplateById(baseMapper.getTargetEntity(), list);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :  first this upsert go select by pk if hava update else insert , include if field is null update or insert, return true is insert 、 false is update
     */
    @Override
    public boolean upsert(T t) {
        return baseMapper.upsert(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description :   first this upsert go select by pk if hava update else insert ,if field is null no update or no insert, return true is insert 、 false is update
     */
    @Override
    public boolean upsert_Selective(T t) {
        return baseMapper.getSQLManager().upsertByTemplate(t);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/20
     * @Description : delete this table by primary key , return delete success length
     */
    @Override
    public int delete_ByPK(Object pk) {
        return baseMapper.deleteById(pk);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/21
     * @Description : delete this table by primary key Array , return delete success length
     */
    @Override
    public int delete_ByPKArray(Object[] PkArray) {
        if (PkArray.length == 0)
            return 0;

        List<Object> PKList = Arrays.asList(PkArray);
        // find primary key column
        String PK_Column = "";
        SQLManager sqlManager = baseMapper.getSQLManager();
        Class clazz = baseMapper.getTargetEntity();
        NameConversion nameConversion = sqlManager.getDbStyle().getNameConversion();
        String tableName = nameConversion.getTableName(baseMapper.getTargetEntity());
        TableDesc table = sqlManager.getMetaDataManager().getTable(tableName);
        ClassDesc classDesc = table.genClassDesc(clazz, nameConversion);

        List<String> colIds = classDesc.getIdCols();
        List<String> propertieIds = classDesc.getIdAttrs();
        if (colIds.size() == 0 || propertieIds.size() == 0) {
            throw new BeetlSQLException(BeetlSQLException.ID_NOT_FOUND, "主键未发现," + clazz.getName() + ",检查数据库表定义或者NameConversion");
        }
        KeyWordHandler keyWordHandler = new DefaultKeyWordHandler();
        Iterator<String> colIt = colIds.iterator();
        Iterator<String> propertieIt = propertieIds.iterator();
        if (colIt.hasNext() && propertieIt.hasNext()) {
            String colId = colIt.next();
            PK_Column = keyWordHandler.getCol(colId);
            System.out.print(PK_Column + "---------------");
            while (colIt.hasNext() && propertieIt.hasNext()) {
                colId = colIt.next();
                PK_Column = keyWordHandler.getCol(colId);
                System.out.print(PK_Column + "++++++++++++++");
            }
        }
        Query<T> query = sqlManager.query(clazz);
        return query.andIn(PK_Column, PKList).delete();
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/21
     * @Description : find page of page and pageSize , return totalRow 、totalpage、list
     */
    @Override
    public PageResult<T> find_Page(long page, int pageSize) {
        return this.find_Page(page, pageSize, null, null);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/21
     * @Description : find page of page and pageSize and t , return totalRow 、totalpage、list
     */
    @Override
    public PageResult<T> find_Page(long page, int pageSize, T t) {
        return this.find_Page(page, pageSize, t, null);
    }

    /**
     * @Author : Yan
     * @Create : 2019/12/21
     * @Description : find page of page and pageSize and t and orderBy, return totalRow 、totalpage、list
     */
    @Override
    public PageResult<T> find_Page(long page, int pageSize, T t, String orderBy) {
        PageRequest<T> pageRequest = DefaultPageRequest.of(page, pageSize);
        SQLManager sqlManager = baseMapper.getSQLManager();
        LambdaQuery<T> lambdaQuery = baseMapper.createLambdaQuery();
        ClassDesc classDesc = sqlManager.getClassDesc(baseMapper.getTargetEntity());

        if (t != null) {
            Map<String, Object> parasMap = BeanUtil.beanToMap(t);

            Set<String> properties = classDesc.getAttrs();
            Set<String> cols = classDesc.getInCols();
            KeyWordHandler keyWordHandler = new DefaultKeyWordHandler();
            Iterator<String> colIt = cols.iterator();
            Iterator<String> propertieIt = properties.iterator();

            while (colIt.hasNext() && propertieIt.hasNext()) {
                String col = colIt.next();
                String propertie = propertieIt.next();
                String column = keyWordHandler.getCol(col);
                if (parasMap.get(propertie) != null) {
                    lambdaQuery.andEq(column, parasMap.get(propertie));
                }
            }
        }

        if (orderBy != null) {
            lambdaQuery.orderBy(orderBy);
        } else {
            // 获取主键
            List<String> colIds = classDesc.getIdCols();
            if (colIds.size() == 0) {
                throw new BeetlSQLException(BeetlSQLException.ID_NOT_FOUND, "主键未发现," + baseMapper.getTargetEntity().getName() + ",检查数据库表定义或者NameConversion");
            }
            Iterator<String> colIdIt = colIds.iterator();
            while (colIdIt.hasNext()) {
                String colId = colIdIt.next();
                lambdaQuery.orderBy(colId);
            }
        }

        return lambdaQuery.page(pageRequest.getPageNumber(), pageRequest.getPageSize());
    }

}
